﻿#include "Commands.h"
#include "YImageDrawer.h"

//class QGraphicsRectItem;
//class QGraphicsEllipseItem;
//class QGraphicsPolygonItem;
namespace Y_Image_Drawer_GUI {
    // 添加元素时undo/redo
    AddCommand::AddCommand(QGraphicsItem* graphicsItem, QGraphicsScene* scene, QUndoCommand *parent)
        : QUndoCommand(parent), m_GraphicsScene(scene)
    {
        m_GraphicsItem = graphicsItem;
        initialPosition = QPointF(graphicsItem->pos().x(), graphicsItem->pos().y());
        scene->update();
//        setText(QObject::tr("Add %1")
//            .arg(createCommandString(graphicsItem, initialPosition)));
    };

    AddCommand::~AddCommand(){
    }

    void AddCommand::undo()
    {
//        m_GraphicsScene->removeItem(m_GraphicsItem);
        // 为选区位置变更时恢复元素位置，删除时改为hide，添加时改为show
        m_GraphicsItem->hide();
        m_GraphicsScene->update();
    }

    void AddCommand::redo()
    {
//        m_GraphicsScene->addItem(m_GraphicsItem);
//        m_GraphicsItem->setPos(initialPosition);
//        m_GraphicsScene->clearSelection();
        // 为选区位置变更时恢复元素位置，删除时改为hide，添加时改为show
        m_GraphicsItem->show();
        m_GraphicsScene->update();
    }

    // 删除元素时undo/redo
    DeleteCommand::DeleteCommand(QGraphicsScene *scene, QUndoCommand *parent)
        : QUndoCommand(parent), m_GraphicsScene(scene)
    {
        QList<QGraphicsItem *> list = m_GraphicsScene->selectedItems();
        list.first()->setSelected(false);
        m_GraphicsItem = static_cast<QGraphicsItem *>(list.first());
//        setText(QObject::tr("Delete %1")
//            .arg(createCommandString(m_GraphicsItem, m_GraphicsItem->pos())));
    };

    void DeleteCommand::undo()
    {
//        YGraphicsItem* item = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
//        if(item->itemType == YImageDrawer::Tip){
//            m_GraphicsItem->show();
//        }else{
//            m_GraphicsScene->addItem(m_GraphicsItem);
//        }
        // 为选区位置变更时恢复元素位置，删除时改为hide，添加时改为show
        m_GraphicsItem->show();
        m_GraphicsScene->update();
    }

    void DeleteCommand::redo()
    {
//        YGraphicsItem* item = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
//        // 由于Tip删除时编号会重新排列，redo/undo时无法恢复，删除改为隐藏
//        if(item->itemType == YImageDrawer::Tip){
//            m_GraphicsItem->hide();
//        }else{
//            m_GraphicsScene->removeItem(m_GraphicsItem);
//        }
        // 为选区位置变更时恢复元素位置，删除时改为hide，添加时改为show
        m_GraphicsItem->hide();
        m_GraphicsScene->update();
    }

    // 鼠标移动元素时undo/redo
    MoveCommand::MoveCommand(QGraphicsItem *graphicsItem, const QPointF &oldPos, const QPoint &oldLastPos, std::function<void()> func_ptr_makePath, std::function<void()> func_ptr_showChange, QUndoCommand *parent)
        : QUndoCommand(parent), m_GraphicsItem(graphicsItem), m_oldPos(oldPos), newPos(graphicsItem->pos())
        , m_oldLastPos(oldLastPos), newLastPos(dynamic_cast<YGraphicsItem*>(m_GraphicsItem)->lastPos)
        , m_func_ptr_makePath(func_ptr_makePath), m_func_ptr_showChange(func_ptr_showChange)
    {
    };

    void MoveCommand::undo()
    {
        m_GraphicsItem->setPos(m_oldPos);
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        if(yitem->itemType == YImageDrawer::Arrow){
//            QPointF diffPos = m_oldPos - newPos;
//            yitem->lastPos = QPoint(QPointF(yitem->lastPos).x() + diffPos.x(), QPointF(yitem->lastPos).y() + diffPos.y());
            yitem->lastPos = m_oldLastPos;
            if(m_func_ptr_makePath != nullptr){
                m_func_ptr_makePath();
            }
            if(m_func_ptr_showChange != nullptr){
//                m_func_ptr_showChange();
            }
        }
//        yitem->reChangePos();
        m_GraphicsItem->update();
        m_GraphicsItem->scene()->update();
//        setText(QObject::tr("Move %1")
//            .arg(createCommandString(m_GraphicsItem, newPos)));
    }

    void MoveCommand::redo()
    {
        m_GraphicsItem->setPos(newPos);
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        if(yitem->itemType == YImageDrawer::Arrow){
//            QPointF diffPos = newPos - m_oldPos;
//            yitem->lastPos = QPoint(QPointF(yitem->lastPos).x() + diffPos.x(), QPointF(yitem->lastPos).y() + diffPos.y());
            yitem->lastPos = newLastPos;
            if(m_func_ptr_makePath != nullptr){
                m_func_ptr_makePath();
            }
            if(m_func_ptr_showChange != nullptr){
//                m_func_ptr_showChange();
            }
        }
//        yitem->reChangePos();
        m_GraphicsItem->update();
        m_GraphicsItem->scene()->update();
//        setText(QObject::tr("Move %1")
//            .arg(createCommandString(m_GraphicsItem, newPos)));
    }

    // 颜色变更时undo/redo
    ChangeItemColorCommand::ChangeItemColorCommand(QGraphicsItem *graphicsItem, QColor oldColor, YGraphicsTipItemPanel *yGraphicsTipItemPanel, QUndoCommand *parent)
        : QUndoCommand(parent), m_GraphicsItem(graphicsItem), m_YGraphicsTipItemPanel(yGraphicsTipItemPanel)
        , m_oldColor(oldColor), newColor(dynamic_cast<YGraphicsItem*>(graphicsItem)->currentColor)
    {
    };

    void ChangeItemColorCommand::undo()
    {
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        QAbstractGraphicsShapeItem* item = dynamic_cast<QAbstractGraphicsShapeItem*>(m_GraphicsItem);
        if(yitem->itemType == YImageDrawer::Arrow){
            item->setBrush(m_oldColor);
        }else if(yitem->itemType == YImageDrawer::Tip){
//            YGraphicsTipItem* itm = dynamic_cast<YGraphicsTipItem*>(m_GraphicsItem);
//            itm->panel->color = m_oldColor;
            if(m_YGraphicsTipItemPanel != nullptr){
                m_YGraphicsTipItemPanel->color = m_oldColor;
            }
        }else{
            QPen pen = item->pen();
            pen.setColor(m_oldColor);
            item->setPen(pen);
        }
        yitem->currentColor = m_oldColor;
        m_GraphicsItem->scene()->update();
    }

    void ChangeItemColorCommand::redo()
    {
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        QAbstractGraphicsShapeItem* item = dynamic_cast<QAbstractGraphicsShapeItem*>(m_GraphicsItem);
        if(yitem->itemType == YImageDrawer::Arrow){
            item->setBrush(newColor);
        }else if(yitem->itemType == YImageDrawer::Tip){
//            YGraphicsTipItem* itm = dynamic_cast<YGraphicsTipItem*>(m_GraphicsItem);
//            itm->panel->color = newColor;
            if(m_YGraphicsTipItemPanel != nullptr){
                m_YGraphicsTipItemPanel->color = newColor;
            }
        }else{
            QPen pen = item->pen();
            pen.setColor(newColor);
            item->setPen(pen);
        }
        yitem->currentColor = newColor;
        m_GraphicsItem->scene()->update();
    }

    // 文字颜色变更时undo/redo
    ChangeTextItemColorCommand::ChangeTextItemColorCommand(QGraphicsItem *graphicsItem, QColor oldColor, std::function<void()> func_ptr_setFontColor, QUndoCommand *parent)
        : QUndoCommand(parent), m_GraphicsItem(graphicsItem)
        , m_oldColor(oldColor), newColor(dynamic_cast<YGraphicsItem*>(graphicsItem)->currentColor), m_func_ptr_setFontColor(func_ptr_setFontColor)
    {
    };

    void ChangeTextItemColorCommand::undo()
    {
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        if(yitem->itemType == YImageDrawer::Text){
            yitem->currentColor = m_oldColor;
            if(m_func_ptr_setFontColor != nullptr){
                m_func_ptr_setFontColor();
            }
        }
        m_GraphicsItem->scene()->update();
    }

    void ChangeTextItemColorCommand::redo()
    {
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        if(yitem->itemType == YImageDrawer::Text){
            yitem->currentColor = newColor;
            if(m_func_ptr_setFontColor != nullptr){
                m_func_ptr_setFontColor();
            }
        }
        m_GraphicsItem->scene()->update();
    }

    // 文字size变更时undo/redo
    ChangeTextItemSizeCommand::ChangeTextItemSizeCommand(QGraphicsItem *graphicsItem, int oldSize, std::function<void()> func_ptr_setFontSize, QUndoCommand *parent)
        : QUndoCommand(parent), m_GraphicsItem(graphicsItem)
        , m_oldSize(oldSize), newSize(dynamic_cast<YGraphicsItem*>(graphicsItem)->currentSize), m_func_ptr_setFontSize(func_ptr_setFontSize)
    {
    };

    void ChangeTextItemSizeCommand::undo()
    {
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        if(yitem->itemType == YImageDrawer::Text || yitem->itemType == YImageDrawer::Tip){
            yitem->currentSize = m_oldSize;
            if(m_func_ptr_setFontSize != nullptr){
                m_func_ptr_setFontSize();
            }
        }
        m_GraphicsItem->scene()->update();
    }

    void ChangeTextItemSizeCommand::redo()
    {
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        if(yitem->itemType == YImageDrawer::Text || yitem->itemType == YImageDrawer::Tip){
            yitem->currentSize = newSize;
            if(m_func_ptr_setFontSize != nullptr){
                m_func_ptr_setFontSize();
            }
        }
        m_GraphicsItem->scene()->update();
    }

    // 文字Weight变更时undo/redo
    ChangeTextItemWeightCommand::ChangeTextItemWeightCommand(QGraphicsItem *graphicsItem, int oldWeight, bool oldBold, std::function<void()> func_ptr_setFontWeight, QUndoCommand *parent)
        : QUndoCommand(parent), m_GraphicsItem(graphicsItem)
        , m_oldWeight(oldWeight), newWeight(dynamic_cast<YGraphicsItem*>(graphicsItem)->currentWeight)
        , m_oldBold(oldBold), newBold(dynamic_cast<YGraphicsItem*>(graphicsItem)->currentFontIsBold)
        , m_func_ptr_setFontWeight(func_ptr_setFontWeight)
    {
    };

    void ChangeTextItemWeightCommand::undo()
    {
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        if(yitem->itemType == YImageDrawer::Text || yitem->itemType == YImageDrawer::Tip){
            yitem->currentWeight = m_oldWeight;
            yitem->currentFontIsBold = m_oldBold;
            if(m_func_ptr_setFontWeight != nullptr){
                m_func_ptr_setFontWeight();
            }
        }
        m_GraphicsItem->scene()->update();
    }

    void ChangeTextItemWeightCommand::redo()
    {
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        if(yitem->itemType == YImageDrawer::Text || yitem->itemType == YImageDrawer::Tip){
            yitem->currentWeight = newWeight;
            yitem->currentFontIsBold = newBold;
            if(m_func_ptr_setFontWeight != nullptr){
                m_func_ptr_setFontWeight();
            }
        }
        m_GraphicsItem->scene()->update();
    }

    // 粗细变更时undo/redo
    ChangeItemThicknessCommand::ChangeItemThicknessCommand(QGraphicsItem *graphicsItem, int oldThickness, std::function<void()> func_ptr_reChangePos, std::function<void()> func_ptr_makePath, QUndoCommand *parent)
        : QUndoCommand(parent), m_GraphicsItem(graphicsItem)
        , m_oldThickness(oldThickness), newThickness(dynamic_cast<YGraphicsItem*>(graphicsItem)->currentThickness)
        , m_func_ptr_reChangePos(func_ptr_reChangePos), m_func_ptr_makePath(func_ptr_makePath)
    {
    };

    void ChangeItemThicknessCommand::undo()
    {
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        QAbstractGraphicsShapeItem* item = dynamic_cast<QAbstractGraphicsShapeItem*>(m_GraphicsItem);
        QPen pen = item->pen();
        pen.setWidth(m_oldThickness);
        item->setPen(pen);
        yitem->currentThickness = m_oldThickness;
        if(m_func_ptr_reChangePos != nullptr){
            m_func_ptr_reChangePos();
        }
        if(m_func_ptr_makePath != nullptr){
            m_func_ptr_makePath();
        }
        m_GraphicsItem->scene()->update();
    }

    void ChangeItemThicknessCommand::redo()
    {
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        QAbstractGraphicsShapeItem* item = dynamic_cast<QAbstractGraphicsShapeItem*>(m_GraphicsItem);
        QPen pen = item->pen();
        pen.setWidth(newThickness);
        item->setPen(pen);
        yitem->currentThickness = newThickness;
        if(m_func_ptr_reChangePos != nullptr){
            m_func_ptr_reChangePos();
        }
        if(m_func_ptr_makePath != nullptr){
            m_func_ptr_makePath();
        }
        m_GraphicsItem->scene()->update();
    }

    // Rect大小变更时undo/redo
    ChangeRectItemSizeCommand::ChangeRectItemSizeCommand(QGraphicsItem* graphicsItem, const QPointF &oldPos, const QRectF &oldRect, const QSizeF &oldSize, std::function<void()> func_ptr_reChangePos, QUndoCommand *parent)
        : QUndoCommand(parent), m_GraphicsItem(graphicsItem), m_oldPos(oldPos), newPos(graphicsItem->pos())
        , m_oldRect(oldRect), newRect(dynamic_cast<QGraphicsRectItem*>(m_GraphicsItem)->rect())
        , m_oldSize(oldSize), newSize(graphicsItem->boundingRect().size())
        , m_func_ptr_reChangePos(func_ptr_reChangePos)
    {
    };

    void ChangeRectItemSizeCommand::undo()
    {
        m_GraphicsItem->setPos(m_oldPos);
        QGraphicsRectItem* rectItem = dynamic_cast<QGraphicsRectItem*>(m_GraphicsItem);
        rectItem->setRect(m_oldRect);
        if(m_func_ptr_reChangePos != nullptr){
            m_func_ptr_reChangePos();
        }
        m_GraphicsItem->scene()->update();
    }

    void ChangeRectItemSizeCommand::redo()
    {
        m_GraphicsItem->setPos(newPos);
        QGraphicsRectItem* rectItem = dynamic_cast<QGraphicsRectItem*>(m_GraphicsItem);
        rectItem->setRect(newRect);
        if(m_func_ptr_reChangePos != nullptr){
            m_func_ptr_reChangePos();
        }
        m_GraphicsItem->scene()->update();
    }

    // Ellipse大小变更时undo/redo
    ChangeEllipseItemSizeCommand::ChangeEllipseItemSizeCommand(QGraphicsItem* graphicsItem, const QPointF &oldPos, const QRectF &oldRect, const QSizeF &oldSize, std::function<void()> func_ptr_reChangePos, QUndoCommand *parent)
        : QUndoCommand(parent), m_GraphicsItem(graphicsItem), m_oldPos(oldPos), newPos(graphicsItem->pos())
        , m_oldRect(oldRect), newRect(dynamic_cast<QGraphicsEllipseItem*>(m_GraphicsItem)->rect())
        , m_oldSize(oldSize), newSize(graphicsItem->boundingRect().size())
        , m_func_ptr_reChangePos(func_ptr_reChangePos)
    {
    };

    void ChangeEllipseItemSizeCommand::undo()
    {
        m_GraphicsItem->setPos(m_oldPos);
        QGraphicsEllipseItem* ellipseItem = dynamic_cast<QGraphicsEllipseItem*>(m_GraphicsItem);
        ellipseItem->setRect(m_oldRect);
        if(m_func_ptr_reChangePos != nullptr){
            m_func_ptr_reChangePos();
        }
        m_GraphicsItem->scene()->update();
    }

    void ChangeEllipseItemSizeCommand::redo()
    {
        m_GraphicsItem->setPos(newPos);
        QGraphicsEllipseItem* ellipseItem = dynamic_cast<QGraphicsEllipseItem*>(m_GraphicsItem);
        ellipseItem->setRect(newRect);
        if(m_func_ptr_reChangePos != nullptr){
            m_func_ptr_reChangePos();
        }
        m_GraphicsItem->scene()->update();
    }

    // Arrow大小变更时undo/redo
    ChangeArrowItemSizeCommand::ChangeArrowItemSizeCommand(QGraphicsItem* graphicsItem, const QPointF &oldPos, const QPoint &oldLastPos, std::function<void()> func_ptr_makePath, QUndoCommand *parent)
        : QUndoCommand(parent), m_GraphicsItem(graphicsItem), m_oldPos(oldPos), newPos(graphicsItem->pos())
        , m_oldLastPos(oldLastPos), newLastPos(dynamic_cast<YGraphicsItem*>(m_GraphicsItem)->lastPos)
        , m_func_ptr_makePath(func_ptr_makePath)
    {
    };

    void ChangeArrowItemSizeCommand::undo()
    {
        m_GraphicsItem->setPos(m_oldPos);
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        yitem->lastPos = m_oldLastPos;
        if(m_func_ptr_makePath != nullptr){
            m_func_ptr_makePath();
        }
        m_GraphicsItem->scene()->update();
    }

    void ChangeArrowItemSizeCommand::redo()
    {
        m_GraphicsItem->setPos(newPos);
        YGraphicsItem* yitem = dynamic_cast<YGraphicsItem*>(m_GraphicsItem);
        yitem->lastPos = newLastPos;
        if(m_func_ptr_makePath != nullptr){
            m_func_ptr_makePath();
        }
        m_GraphicsItem->scene()->update();
    }

//    // 大小变更时undo/redo
//    ChangeItemSizeCommand::ChangeItemSizeCommand(QGraphicsItem *graphicsItem, const QPointF &oldPos, const QPoint &oldLastPos, const QRectF &oldRect, const QSizeF &oldSize, std::function<void()> func_ptr_reChangePos, QUndoCommand *parent)
//        : QUndoCommand(parent), m_GraphicsItem(graphicsItem), m_oldSize(oldSize), newSize(graphicsItem->boundingRect().size())
//        , m_oldLastPos(oldLastPos), newLastPos(dynamic_cast<YGraphicsItem*>(m_GraphicsItem)->lastPos)
//        , m_oldRect(oldRect), newRect(dynamic_cast<QGraphicsEllipseItem*>(m_GraphicsItem)->rect())
//        , m_func_ptr_reChangePos(func_ptr_reChangePos)
//    {
//    }

//    void ChangeItemSizeCommand::undo()
//    {
//        m_GraphicsItem->boundingRect()
//        m_GraphicsItem->boundingRect().setSize(m_oldSize);
//        m_GraphicsItem->scene()->update();
//    }

//    void ChangeItemSizeCommand::redo()
//    {
//        m_GraphicsItem->boundingRect().setSize(newSize);
//        m_GraphicsItem->scene()->update();
//    }

    QString createCommandString(QGraphicsItem *item, const QPointF &pos)
    {
//        YGraphicsItem* itm = dynamic_cast<YGraphicsItem*>(item);
        return QObject::tr("%1 at (%2, %3)")
            .arg("aaa")
            .arg(pos.x()).arg(pos.y());
    }
}

